#region Disclaimer by Teo Lachev
/*============================================================================
  The CustomDataExtension sample uses code from the Microsoft File Share Data 
  Processing Extension Sample (http://msdn2.microsoft.com/en-us/library/ms160918.aspx). 
  The orginal code base has been modified whenever needed to re-purpose the 
  extension to support ADO.NET datasets. Most code changes are implemented in the 
  DsDataReader class.
===========================================================================*/
#endregion

using System;
using System.Collections;
using Microsoft.ReportingServices.DataProcessing;
using System.IO;
using System.Globalization;
using System.Security;
using System.Security.Principal;
using System.Data;
using System.Diagnostics;
using System.Security.Permissions;

namespace Prologika.RS.Extensibility.CustomDataExtension
{
    /// <summary>
    /// Represents a data reader
    /// </summary>
   public class DsDataReader : Microsoft.ReportingServices.DataProcessing.IDataReader
   {
      
      private DsConnectionWrapper		m_connection = null;
      private string					m_cmdText =  null;
      private DsDataParameterCollection m_parameters = null;
      private DataSet					m_dataset = null;
      private DataTable					m_datatable = null;
	  private DataRow					m_dataRow = null;
      internal IEnumerator				m_ie;
      
      // maximum size in bytes

      /*
      * Because the user should not be able to directly create a 
      * DataReader object, the constructors are
      * marked as internal.
      */
      internal DsDataReader()
      {
         // TODO: Implement default constructor
      }

      internal DsDataReader(string cmdText)
      {
         // TODO: Implement command text only construtor
      }

      internal DsDataReader(DsConnectionWrapper connection, string cmdText )
      {
         m_connection  = connection;
      }

	   internal DsDataReader( DsConnectionWrapper connection, string cmdText, DsDataParameterCollection parameters)
	   {
		   System.Diagnostics.Trace.WriteLine(String.Format ("DsConnection: {0}, cmdText: {1}, WsParameterCollection: {2}", connection.ConnectionString, cmdText, parameters.Count.ToString()));
		   m_connection  = connection;
		   m_cmdText = cmdText;
		   m_parameters = parameters;
	   }
      /****
      * METHODS / PROPERTIES FROM IDataReader.
      ****/
      /// <summary>
      /// Called repeatedly when the report is processed for each row
      /// </summary>
      /// <returns></returns>
      public bool Read()
      {
         if (m_ie != null)
         {
            return  m_ie.MoveNext();
         }
         return false;
      }

      /****
      * METHODS / PROPERTIES FROM IDataRecord.
      ****/
	   /// <summary>
	   /// Returns the number of columns in the table
	   /// </summary>
      public int FieldCount
      {
         // Return the count of the number of columns, which in
         // this case is the size of the column metadata
         // array.
         get { return (m_datatable.Columns.Count); }
      }

	   /// <summary>
	   /// Returns the name of the column
	   /// </summary>
	   /// <param name="i"></param>
	   /// <returns></returns>
      public string GetName(int i)
      {
         return (m_datatable.Columns[i].ColumnName);
      }
	/// <summary>
	/// Returns the column type
	/// </summary>
	/// <param name="i"></param>
	/// <returns></returns>
      public Type GetFieldType(int i)
      {
         // Return the actual Type class for the data type.
         return (m_datatable.Columns[i].DataType);
      }
	/// <summary>
	/// Returns the column value
	/// </summary>
	/// <param name="i"></param>
	/// <returns></returns>
      public Object GetValue(int i)
      {
         return ((DataRow)m_ie.Current)[i];
      }
		/// <summary>
		/// Returns the column ordinal position
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
      public int GetOrdinal(string name)
      {
         // Look for the ordinal of the column with the same name and return it.
         // Returns -1 if not found
		 return m_datatable.Columns[name].Ordinal;

      }

      /*
      * Implementation specific methods.
      */
	   /// <summary>
	   /// Loads the dataset
	   /// </summary>
	  /// <remarks>
	  /// During desing time (query and layout tab) returns an empty dataset
	  /// During runtime, it binds to the whatever is passed to the @DataSource parameter
	  /// </remarks>
      internal void LoadDataset()
      {
	    
	    string dataSource = null;

		// attempt to get the DataSource parameter
	    DsDataParameter parameter =  m_parameters.GetByName(Util.DATA_SOURCE) as DsDataParameter;
	    Debug.Assert (parameter!=null, "DataSource parameter not specified.");
		if (parameter==null) throw new ArgumentException("DataSource parameter not specified.");
		dataSource = parameter.Value.ToString();
		Debug.Assert (dataSource!=null, "DataSource parameter not specified.");
	    if (dataSource==null) throw new ArgumentException("DataSource parameter not specified.");

		// load the dataset
		m_dataset = GetDataSet(dataSource); 

		Trace.WriteLine(String.Format ("Referencing dataset table: {0}", m_cmdText.Trim().ToLower()));
	    // get the dataset table
		if (m_cmdText.Trim().ToLower()=="nothing")
			m_datatable = m_dataset.Tables[0];
		else
		{	  
			// get the specified table
			Debug.Assert(m_dataset.Tables[m_cmdText]!=null, String.Format("Data member {0} not found.", m_cmdText) );
			if (m_dataset.Tables[m_cmdText]==null) throw new ArgumentException(String.Format("Data member {0} not found.", m_cmdText));
			m_datatable = m_dataset.Tables[m_cmdText];
		}
		// set the row enumerator
		m_ie = m_datatable.Rows.GetEnumerator();
		 
      }

      public void Dispose() 
      {
      }

	   /// <summary>
	   /// Loads the dataset from its XML serialized copy or file
	   /// </summary>
	   /// <param name="dataSource">The XML serialized copy of file path</param>
	   /// <returns></returns>
	   private DataSet GetDataSet(string dataSource)
	   {
		DataSet dataset = new DataSet();

		// is this XML or file path?
		if (dataSource.IndexOf("<")>=0)
		{
			// xml
			StringReader reader =  new StringReader(dataSource);
			try 
			{
				dataset.ReadXml(reader);
			}
			catch (System.Exception ex)
			{
				throw ex;
			}

		}
		else	
		{
			// file
			FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Read, dataSource);
			try
			{
				permission.Assert();
			}
			catch {}
			try
			{	
				//stream =  new FileStream (dataSource, System.IO.FileMode.Open);
				dataset.ReadXml(dataSource);
			}
			finally 
			{
				//stream.Close();
			}
		}

	    return dataset;

	   }

	}
}

